﻿// <copyright file="Tools.cs" company="Ecole Normale Supérieure">
// Released under GPLv2
// </copyright>
// <summary>Contains tools used by Persistence.</summary>

namespace Sqwarea.Persistence
{
    using System;
    using System.Collections.Generic;
    using System.Drawing;
    using System.Globalization;
    using System.Security.Cryptography;
    using System.Text;

    /// <summary>
    /// Static class for useful function.
    /// </summary>
    public static class Tools
    {
        /// <summary>
        /// Format used to convert int and longs to strings
        /// </summary>
        public static readonly NumberFormatInfo NumberFormat = CultureInfo.InvariantCulture.NumberFormat;
        
        /// <summary>
        /// Random generator
        /// </summary>
        private static Random _random = new Random();

        /// <summary>
        /// Return a random id which can be used as a name on the cloud (alphanumeric low case)
        /// </summary>
        /// <returns>See summary.</returns>
        public static string RandId()
        {
            return Tools._random.Next(1000000000).ToString(Tools.NumberFormat);
        }

        /// <summary>
        /// Return a random double (used by GameLogic.UserStarter)
        /// </summary>
        /// <returns>See summary.</returns>
        public static double RandDouble()
        {
            return Tools._random.NextDouble();
        }

        /// <summary>
        /// Create an IEnumerable containing the integers from start to start+count-1.
        /// </summary>
        /// <param name="start">The first integer of the IEnumerable.</param>
        /// <param name="count">The last integer of the IEnumerable.</param>
        /// <returns>See summary.</returns>
        public static IEnumerable<long> Range(long start, long count)
        {
            for (long i = start; i < start + count; i++)
            {
                yield return i;
            }
        }

        /// <summary>
        /// Flat a bidimensionnal array of elements of type T.
        /// </summary>
        /// <typeparam name="T">Type of elements of the array</typeparam>
        /// <param name="array">Array to flat</param>
        /// <returns>The flatten array</returns>
        public static T[] FlatArray<T>(T[,] array)
        {
            var result = new T[array.GetLength(0) * array.GetLength(1)];

            for (int i = 0; i < array.GetLength(0); i++)
            {
                for (int j = 0; j < array.GetLength(1); j++)
                {
                    result[(i * array.GetLength(1)) + j] = array[i, j];
                }
            }

            return result;
        }

        /// <summary>
        /// Hash an input string and return the hash as a 32 character hexadecimal string.
        /// </summary>
        /// <param name="input">string to hash</param>
        /// <returns>md5 hash of the string</returns>
        public static string GetMD5Hash(string input)
        {
            // Create a new instance of the MD5CryptoServiceProvider object.
            MD5 hasher = MD5.Create();

            // Convert the input string to a byte array and compute the hash.
            byte[] data = hasher.ComputeHash(Encoding.Default.GetBytes(input));

            // Create a new Stringbuilder to collect the bytes
            // and create a string.
            var stringBuilder = new StringBuilder();

            // Loop through each byte of the hashed data 
            // and format each one as a hexadecimal string.
            for (int i = 0; i < data.Length; i++)
            {
                stringBuilder.Append(data[i].ToString("x2", CultureInfo.InvariantCulture));
            }

            // Return the hexadecimal string.
            return stringBuilder.ToString();
        }

        /// <summary>
        /// Return a number such as if we added y to x then the result would be increased by 1 
        /// (no problems in 0 ; Div(-1,20) = -1)
        /// </summary>
        /// <param name="x">number that get divided</param>
        /// <param name="y">number that divide</param>
        /// <returns>x correctly divided by y</returns>
        public static int Div(int x, int y)
        {
            return (x - ((y - 1) * Convert.ToInt32(x < 0))) / y;
        }

        /// <summary>
        /// use the format : xn?[0-9]+yn?[0-9]+
        /// n standing for "negative"
        /// Not sure if really necessary as RowKey/PartitionKey seems to accept all character though...
        /// </summary>
        /// <param name="point">the point to be transformed in string</param>
        /// <returns>a string designing the point in alphanumerical-only characters</returns>
        public static string ToAlphaString(this Point point)
        {
            ////string result = "x";
            ////if (point.X < 0)
            ////{
            ////    result += "n";
            ////}

            ////result += Math.Abs(point.X).ToString(Tools.NumberFormat);
            ////result += "y";
            ////if (point.Y < 0)
            ////{
            ////    result += "n";
            ////}

            ////result += Math.Abs(point.Y).ToString(Tools.NumberFormat);
            ////return result;

            return "x" + point.X.ToString(Tools.NumberFormat) +
                   "y" + point.Y.ToString(Tools.NumberFormat);
        }
    }
}
